package Dominio;

import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Vector;

/**
 * Es la clase para representar los temas en la aplicacion
 * @author Sandra Crespo
 */
public class Tema implements Serializable {

    private String nombre;
    private Vector<PalabraParaAnadir> llpalabra;
    private Vector<NoticiaClasificada> llnoticia;
   private String secciones;
    /** 
     * Crea un Tema vacio
     */
    public Tema() {
        /*** {PRE:-}
         * {POST: se crea un tema vacio}
         */
        llpalabra = new Vector<PalabraParaAnadir>();
        llnoticia = new Vector<NoticiaClasificada>();
    }

    /** 
     * Crea un Tema cuyo nombre sea t
     * @param t Nombre del Tema
     */
    public Tema(String t, String secc) {
        /*** {PRE:-}
         * {POST: se crea un tema con el nombre t}
         */
        nombre = t;
        secciones=secc;
        llpalabra = new Vector<PalabraParaAnadir>();
        llnoticia = new Vector<NoticiaClasificada>();
    }

    /** 
     * Consulta el Nombre del tema
     * @return devuelve el nombre del tema
     */
    public String getNombre() {
        /*** {PRE:-}
         * {POST:devuelve el nombre del Tema}*/
        return nombre;
    }
    
         
    public String getSeccion(){
        return secciones;
    }

    /** 
     * Consulta el las palabras que estan asociadas con el Tema
     * @return devuelve el vector con los punteros a las palabras asociadas con el tema
     */
    public Vector<PalabraParaAnadir> getPalabras() {
        /*** {PRE:-}
         * {POST:devuelve un Vector de punteros de las PalabraParaAnadir del Tema. El Vector puede no tener ninguna PalabraParaAnadir dentro}*/
        return llpalabra;
    }

    /** 
     * Consulta si la palabra esta asociada a tema
     * @param palabra es el nombre de la palabra que se desea consultar si es palabra clave del tema.
     * @return devuelve un booleano que indica si hay una palabra asociada con el tema que tenga el nombre.
     */
    public boolean esPalabraClave(String palabra) {
        /*** {PRE:-}
         * {POST:true: si hay una PalabraParaAnadir asociada a Tema cuyo nombre sea palabra. false: si no hay ninguna PalabraParaAnadir asociada a Tema cuyo nombre sea palabra}*/
        for (PalabraParaAnadir p : llpalabra) {
            if (palabra.equals(p.getValor())) {
                return true;
            }
        }
        return false;
    }

    /** 
     * Consulta las noticias clasificadas que tienen asociado el tema.
     * @return devuelve un vector de punteros a las noticias clasificadas que tienen asociado el tema
     */
    public Vector<NoticiaClasificada> getNoticiasClasificadas() {
        /*** {PRE:-}
         * {POST:devuelve un Vector de punteros de las NoticiasClasificadas que sean del Tema. El Vector puede no tener ninguna NoticiaClasificada dentro}*/
        return llnoticia;
    }

    /** 
     * Consulta si la noticia esta asociada al tema
     * @param noticia es el nombre de la notica que se desea consultar si es noticia clasificada del tema.
     * @return deuelve un booleano que indica si hay una noticia asociada con el tema que tenga el nombre.
     */
    public boolean esNoticiaClasificada(String noticia) {
        /*** {PRE:-}
         * {POST:true: si hay una NoticiaClasificada asociada a Tema cuyo titulo sea noticia. false: si no hay ninguna NoticiaClasificada asociada a Tema cuyo titulo sea noticia}*/
        for (NoticiaClasificada not : llnoticia) {
            if (noticia.equals(not.getTitulo())) {
                return true;
            }
        }
        return false;
    }

    /** 
     * Anade una noticia clasificada al tema
     * @param nc es la noticia clasificada que se desea asociar al tema
     * @return devuelve un booleano que indica la noticia clasificada se ha asociado correctamente al tema.
     */
    public boolean addNoticiaClasificada(NoticiaClasificada nc) {
        /*** {PRE:nc!=null y no existe una noticia en la lista llnoticias con el mismo titulo que nc}
         * {POST:true: si la noticiaClasificada nc se ha anadido correctamente. false: si no se ha anadido correctamente}*/
        return llnoticia.add(nc);
    }

    /** 
     * Consulta el numero de noticias clasificadas que estan asociadas con el tema
     * @return devuelve el numero de noticias que estan clasificadas y estan asociadas con el tema.
     */
    public int numeroNoticiasClasificadas() {
        /*** {PRE:-}
         * {POST: devuelve el numero de NoticiasClasificadas asociadas con el Tema}*/
        return llnoticia.size();
    }

    /** 
     * Consulta el numero de palabras que estan asociadas con el tema
     * @return devuelve el numero de palabras que estan asociadas con el tema.
     */
    public int numeroPalabrasTema() {
        /*** {PRE:-}
         * {POST: devuelve el numero de PalabraParaAnadir asociadas al Tema}*/
        return llpalabra.size();
    }

    /** 
     * Anade una palabra al tema
     * @param palabra es la palabra que se desea asociar con el tema
     * @return devuelve un booleano que indica si la palabra se ha correctamente al tema.
     */
    public boolean addPalabra(PalabraParaAnadir palabra) {
        /*** {PRE:palabra!=null y no existe en tema una palabra en la lista llpalabra con el mismo valor que palabra}
         * {POST:true: si la PalabraParaAnadir palabra se ha anadido correctamente. false: si no se ha anadido correctamente}*/
        return llpalabra.add(palabra);
    }

    public double getDistancia(Vector<IdFrec> not, int N, DiccionarioPalabras dp, String seccion) {
        LinkedList<IdFrec> vectorC = new LinkedList<IdFrec>();
        vectorC = this.getVectorCentroide(N, dp);
        for (IdFrec idf : not) {
            PalabraParaAnadir pa = (PalabraParaAnadir) dp.consultarPalabra(idf.id);
            System.out.println(pa.getNApariciones(seccion)+" "+N);
            if (pa.getNApariciones(seccion) != 0) {
                if (N != 0) {
                    idf.frec = idf.frec * Math.log10(N / (double) pa.getNApariciones(seccion));
                }
            }
        }
        double aux = Math.sqrt(cuadrados(not));
        for (IdFrec idF : not) {
            if (aux != 0) {
                idF.frec = idF.frec / aux;
            } else {
                idF.frec = 0;
            }
        }
        Collections.sort(not);
        return distancia(vectorC, not);
    }

    /** 
     * Calcula el vector centroide de la noticia.
     * @param N es el numero de palabras que tenemos en el diccionario.
     * @return devuelve una LinkedList con el id de la palabra y la componente del vector centroide para esa palabra.
     */
    public LinkedList<IdFrec> getVectorCentroide(int N, DiccionarioPalabras dp) {
        /*** {PRE:-}
         * {POST:true: devuelve una LinkedList con el id de la palabra y la componente del vector centroide para esa palabra.El vector puede no tener ningun IdFrec dentro}*/
        LinkedList<IdFrec> vectorC2 = new LinkedList<IdFrec>();
        for (NoticiaClasificada nc : llnoticia) {
            vectorC2 = sumaVectores(vectorC2, nc.frecuencia(N, dp));
        }
        for (IdFrec idF : vectorC2) {
            idF.frec = idF.frec / (llnoticia.size());
        }

        return vectorC2;
    }

    private static LinkedList<IdFrec> sumaVectores(LinkedList<IdFrec> vectorC, Vector<IdFrec> frecuencia) {
        int i = 0;
        int j = 0;
        int N = vectorC.size();
        int M = frecuencia.size();
        LinkedList<IdFrec> aux = new LinkedList<IdFrec>();
        while (i < N && j < M) {
            if (frecuencia.get(j).id == vectorC.get(i).id) {
                IdFrec idF = vectorC.get(i);
                idF.frec = idF.frec + frecuencia.get(j).frec;
                aux.addLast(idF);
                i++;
                j++;
            } else if (vectorC.get(i).id < frecuencia.get(j).id) {
                aux.addLast(vectorC.get(i));
                i++;
            } else if (vectorC.get(i).id > frecuencia.get(j).id) {
                aux.addLast(frecuencia.elementAt(j));
                j++;
            }
        }
        if (i < N) {
            while (i < N) {
                aux.addLast(vectorC.get(i));
                i++;
            }
        }
        if (j < M) {
            while (j < M) {
                aux.addLast(frecuencia.elementAt(j));
                j++;
            }
        }
        return aux;
    }

    private double distancia(LinkedList<IdFrec> vectorC, Vector<IdFrec> not) {
        int i = 0;
        int j = 0;
        int N = vectorC.size();
        int M = not.size();
        double acum = 0;
        LinkedList<IdFrec> aux = new LinkedList<IdFrec>();
        while (i < N && j < M) {
            if (not.get(j).id == vectorC.get(i).id) {
                acum = acum + (not.get(j).frec * vectorC.get(i).frec);
                i++;
                j++;
            } else if (vectorC.get(i).id < not.get(j).id) {
                i++;
            } else if (vectorC.get(i).id > not.get(j).id) {
                j++;
            }
        }
        return acum;
    }

    private double cuadrados(Vector<IdFrec> idF) {
        double acum = 0;
        for (IdFrec idf : idF) {
            acum = acum + (idf.frec * idf.frec);
        }
        return acum;
    }
}
